package com.microservices.yucloud.appweb.config;

import com.microservices.yucloud.appweb.action.*;
import com.microservices.yucloud.appweb.contants.StateMachineBuilderConstants;
import com.microservices.yucloud.appweb.enums.BizOrderEventsEnum;
import com.microservices.yucloud.appweb.enums.BizOrderStatusEnum;
import com.microservices.yucloud.appweb.guard.BizOrderReviewGuard;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.statemachine.StateMachine;
import org.springframework.statemachine.config.StateMachineBuilder;
import org.springframework.stereotype.Component;

import java.util.EnumSet;

/**
 * @author zy
 * @date 2019-08-30 11:17
 **/
@Slf4j
@Component
public class BizOrderStateMachineBuilder implements BaseStateMachineBuilder {

    @Autowired
    private OrderCreateAction orderCreateAction;
    @Autowired
    private OrderComputeAction orderComputeAction;

    @Override
    public String getName() {
        return StateMachineBuilderConstants.BIZ_ORDER_NAME;
    }

    @Override
    public StateMachine<BizOrderStatusEnum, BizOrderEventsEnum> build(BeanFactory beanFactory) throws Exception {
        StateMachineBuilder.Builder<BizOrderStatusEnum, BizOrderEventsEnum> builder = StateMachineBuilder.builder();
        log.info("构建订单流程状态机");
        builder.configureConfiguration()
                .withConfiguration()
                .autoStartup(true)
                .beanFactory(beanFactory)
                .machineId("BizOrderStateMachineId");

        //配置状态机
        builder.configureStates()
                .withStates()
                .initial(BizOrderStatusEnum.INIT)
                .choice(BizOrderStatusEnum.CHECK_REVIEW)
                .choice(BizOrderStatusEnum.GENERATING)
                .choice(BizOrderStatusEnum.SEND_PACKAGING)

                .end(BizOrderStatusEnum.CANCEL)
                .end(BizOrderStatusEnum.CLOSE)
                .end(BizOrderStatusEnum.SUCCESS)
                .states(EnumSet.allOf(BizOrderStatusEnum.class));

        builder.configureTransitions()
                .withExternal()
                .source(BizOrderStatusEnum.INIT).target(BizOrderStatusEnum.CREATED)
                .event(BizOrderEventsEnum.CREATE)
                .action(orderCreateAction, new ErrorHandlerAction())

                .and().withExternal()
                .source(BizOrderStatusEnum.CREATED).target(BizOrderStatusEnum.RECOMMEND)
                .event(BizOrderEventsEnum.COMPUTE)
                .action(orderComputeAction)

                .and().withExternal()
                .source(BizOrderStatusEnum.RECOMMEND).target(BizOrderStatusEnum.CHECK_REVIEW)
                .event(BizOrderEventsEnum.REVIEW)

                .and().withChoice()
                .source(BizOrderStatusEnum.CHECK_REVIEW)
                .first(BizOrderStatusEnum.REVIEWING, new BizOrderReviewGuard(), new OrderReviewAction())
                .last(BizOrderStatusEnum.REVIEW_PASSED)

                .and().withExternal()
                .source(BizOrderStatusEnum.REVIEW_PASSED).target(BizOrderStatusEnum.GENERATING)
                .event(BizOrderEventsEnum.GENERATE)

                .and().withChoice()
                .source(BizOrderStatusEnum.GENERATING)
                .first(BizOrderStatusEnum.GENERATE_SUCCESS, new BizOrderReviewGuard(), new OrderGenerateAction())
                .last(BizOrderStatusEnum.GENERATE_FAIL, new OrderGenerateAction())

                .and().withExternal()
                .source(BizOrderStatusEnum.GENERATE_SUCCESS).target(BizOrderStatusEnum.SEND_PACKAGING)
                .event(BizOrderEventsEnum.SEND_PACKAGE)

                .and().withChoice()
                .source(BizOrderStatusEnum.SEND_PACKAGING)
                .first(BizOrderStatusEnum.SEND_PACKAGE_SUCCESS, new BizOrderReviewGuard(), new OrderGenerateAction())
                .last(BizOrderStatusEnum.SEND_PACKAGE_FAIL, new OrderGenerateAction())

                .and().withExternal()
                .source(BizOrderStatusEnum.SEND_PACKAGE_SUCCESS).target(BizOrderStatusEnum.SUCCESS)
                .event(BizOrderEventsEnum.COMPLETE)
        ;

        return builder.build();
    }

}
